package com.hydra.base.utils;

import com.hydra.base.entity.EsIdEntity;
import com.hydra.base.error.BusinessException;
import com.hydra.base.query.EsQueryBuilder;
import com.hydra.base.resp.Pager;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Query;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.elasticsearch.index.query.QueryBuilders.*;

@Slf4j
public class ESUtil {

    private final ElasticsearchOperations elasticsearchOperations;

    private ESUtil() {
        this.elasticsearchOperations = SpringUtils.getBean(ElasticsearchOperations.class);
    }

    //单例模式
    private volatile static ESUtil instance = null;

    public static ESUtil getInstance(){
        if(instance == null){
            synchronized (ESUtil.class){
                instance = new ESUtil();
            }
        }
        return instance;
    }

    public <T extends EsIdEntity> void checkIndex(Class<T> tClass){
        IndexOperations indexOperations = elasticsearchOperations.indexOps(tClass);
        if(!indexOperations.exists()){
            indexOperations.create();
            indexOperations.createMapping(tClass);
            indexOperations.createSettings(tClass);
        }
    }

    /**
     * 存储数据到ES中。
     * @param data 对象数据
     * @return 对象数据的ESID
     */
    public <T extends EsIdEntity> String save(T data) {
        Class<? extends EsIdEntity> aClass = data.getClass();
        checkIndex(aClass);
        if(FormatUtil.isEmpty(data.getId())){
            data.setId(SnowIdUtil.getInstance().nextId());
        }
        elasticsearchOperations.save(data);
        return data.getId()+"";
    }

    /**
     * 批量写入操作
     * @param saveList  保存列表
     */
    public <T extends EsIdEntity> void saveBatch(List<T> saveList, Class<T> tClass) {
        checkIndex(tClass);
        elasticsearchOperations.save(saveList);
    }


    /**
     * 根据ID删除数据。
     * @param id   ES的ID
     */
    public <T extends EsIdEntity> void deleteById(String id, Class<T> tClass) {
        elasticsearchOperations.delete(id, tClass);
    }

    /**
     * 根据ID删除数据。
     * @param ids   ES的ID数组
     */
    public <T extends EsIdEntity> void deleteByIds(List<String> ids, Class<T> tClass) {
        if (CollectionUtils.isNotEmpty(ids)) {
            for (String id : ids) {
                deleteById(id, tClass);
            }
        }
    }

    /**
     * 删除索引
     */
    public <T extends EsIdEntity> void deleteIndex(Class<T> tClass){
        IndexOperations indexOperations = elasticsearchOperations.indexOps(tClass);
        indexOperations.delete();
    }

    public <T extends EsIdEntity> EsQueryBuilder<T> query(Class<T> tClass){
        return new EsQueryBuilder<>(tClass);
    }

    /*
    *//**
     * 分页查询ES列表数据
     * @param dto           查询对象
     * @param pager         分页对象
     *//*
    public <T extends EsIdEntity> void queryByPage(T dto, Pager<T> pager){
        this.queryByPage(dto, pager, null);
    }
    *//**
     * 分页查询ES列表数据
     * @param dto           查询对象
     * @param pager         分页对象
     *//*
    public <T extends EsIdEntity> void queryByPage(T dto, Pager<T> pager, QueryHandler handler){
        this.queryByPage(dto, pager, null, handler);
    }

    *//**
     * 分页查询ES列表数据
     * @param dto           查询对象
     * @param pager         分页对象
     * @param config        配置每个属性的查询条件
     *//*
    public <T extends EsIdEntity> void queryByPage(T dto, Pager<T> pager, Map<String, QueryConfig> config, QueryHandler handler){
        //分页 ES分页从第0页开始
        int pageNo = pager.getPageNo();
        int pagerSize = pager.getSize();
        if (pagerSize > 1000) {
            throw new BusinessException("查询数据量过大，请补充录入更多查询条件精确查询结果!");
        }

        //检查索引是否存在
        checkIndex(dto.getClass());

        List<Sort.Order> orders = new ArrayList<>();

        if(config == null){
            config = new HashMap<>();
        }
        Class<? extends EsIdEntity> tClass = dto.getClass();
        //查询条件
        BoolQueryBuilder queryBuilder = boolQuery();
        //遍历所有的字段，判断如果不为空则添加进ES查询条件
        Field[] declaredFields = tClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            String prop = declaredField.getName();
            QueryConfig conf = config.get(prop);
            if(conf == null){
                continue;
            }
            //根据配置添加查询条件
            handleBuildQuery(queryBuilder, dto, conf, prop);
            //根据配置处理排序
            if(conf.sort){
                Sort.Direction direction = conf.desc? Sort.Direction.DESC :Sort.Direction.ASC;
                orders.add(new Sort.Order(direction, prop));
            }
        }
        //自定义查询条件
        if(handler != null){
            handler.handle(queryBuilder);
        }



    }*/

    /**
     * 构建查询条件
     */
    /*private <T extends EsIdEntity> void handleBuildQuery(BoolQueryBuilder queryBuilder, T dto, QueryConfig conf, String prop) {
        QueryConfigType type = conf.getType();//配置类型
        QueryBuilder query;//查询条件
        //值不为空，处理成查询条件
        String beanValue = getBeanValue(dto, prop);
        if(QueryConfigType.RangeQuery.equals(type)){//如果配置了range，则处理成范围查询
            query = handleRangeQuery(prop, conf);
            queryBuilder.must(query);
        }else if(StringUtils.isNotBlank(beanValue)){
            if(conf.keyword){//是否带keyword查询
                prop = prop + ".keyword";
            }
            if(QueryConfigType.none.equals(type)){//不处理
                query = null;
            }else if(QueryConfigType.MatchQuery.equals(type)){//如果配置了match，则处理成匹配查询
                query = matchQuery(prop, beanValue.trim());
            }else if(QueryConfigType.WildcardQuery.equals(type)){//如果配置了wildcard，则处理成模糊查询
                query = wildcardQuery(prop, "*"+ beanValue.trim()+"*");
            }else if(QueryConfigType.InQuery.equals(type)){//如果配置了In，则处理成in查询
                String value = beanValue.trim();
                String[] array = value.split(",");
                query = termsQuery(prop, array);
            }else{//默认是匹配查询
                query = termQuery(prop, beanValue.trim());
            }
            if(query != null){
                queryBuilder.must(query);
            }
        }
        //自定义查询条件
        if(conf.handler != null){
            conf.handler.handle(queryBuilder);
        }
    }*/

    /**
     * 处理范围查询
     */
    /*private QueryBuilder handleRangeQuery(String prop, QueryConfig conf) {
        RangeQueryBuilder query = rangeQuery(prop);
        if(FormatUtil.isNotEmpty(conf.lt)){
            query.lt(conf.lt);
        }
        if(FormatUtil.isNotEmpty(conf.gt)){
            query.gt(conf.gt);
        }
        if(FormatUtil.isNotEmpty(conf.lte)){
            query.lte(conf.lte);
        }
        if(FormatUtil.isNotEmpty(conf.gte)){
            query.gte(conf.gte);
        }
        return query;
    }*/


//    /**
//     * 获取bean属性值
//     */
//    private <T extends EsIdEntity> String getBeanValue(T dto, String prop){
//        try {
//            Field field = dto.getClass().getDeclaredField(prop);
//            field.setAccessible(true);
//            return FormatUtil.isNullToString(field.get(dto), StringUtils.EMPTY);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        return null;
//    }

//    /**匹配查询的配置*/
//    public static final QueryConfig MatchQueryConfig = new QueryConfig(QueryConfigType.MatchQuery);
//    /**模糊查询的配置*/
//    public static final QueryConfig WildcardQueryConfig = new QueryConfig(QueryConfigType.WildcardQuery);
//    /**匹配查询的配置*/
//    public static final QueryConfig TermQueryConfig = new QueryConfig(QueryConfigType.TermQuery);
//    /**范围查询的配置*/
//    public static final QueryConfig RangeQueryConfig = new QueryConfig(QueryConfigType.RangeQuery);
//    /**In查询的配置*/
//    public static final QueryConfig InQueryConfig = new QueryConfig(QueryConfigType.InQuery);

//    /**
//     * 查询条件的实体配置
//     */
//    public static class QueryConfig{
//        /**是否匹配查询*/
//        @Getter @Setter
//        QueryConfigType type;
//        /**是否关键字匹配*/
//        @Getter @Setter
//        boolean keyword = false;
//        @Setter
//        boolean sort = false;//是否开启排序
//        @Setter
//        boolean desc = true;//排序方式，默认是倒序
//        @Setter
//        QueryHandler handler;
//        @Setter
//        Object lt;
//        @Setter
//        Object lte;
//        @Setter
//        Object gt;
//        @Setter
//        Object gte;
//        public QueryConfig(QueryConfigType type){
//            this.type = type;
//        }
//    }
//
//    public enum QueryConfigType{
//        //不进行查询
//        none(),
//        //匹配查询
//        MatchQuery(),
//        //模糊查询
//        WildcardQuery(),
//        //匹配查询
//        TermQuery(),
//        //范围查询
//        RangeQuery(),
//        //In查询
//        InQuery();
//    }


}
